#pragma once
#include "Util.hpp"

//------------------------------------
//此文件与MySQL数据库进行交互。
//这个类提供了用户注册、登录验证、根据用户名或ID查询用户信息，
//以及更新用户胜利或失败后的信息等功能。
//------------------------------------
class user_table
{
private:
    MYSQL *_mysql;     // mysql操作句柄
    std::mutex _mutex; // 互斥锁
public:
    user_table(const std::string &host,
               const std::string &username,
               const std::string &password,
               const std::string &dbname,
               uint16_t port = 3306)
    {
        _mysql = mysql_util::mysql_create(host, username, password, dbname, port);
        assert(_mysql != NULL);
    }
    ~user_table()
    {
        if (_mysql != NULL)
        {
            mysql_util::mysql_destory(_mysql);
            _mysql = NULL;
        }
    }
    // 注册新用户
    bool insert(Json::Value &user)
    {
        //校验判断用户名和密码存在
        if(user["username"].isNull() || user["password"].isNull())
        {
            LOG(ERROR,"please input username and password!\n");
            return false;
        }
#define INSERT_USER "insert user value(null,'%s',password('%s'), 1000, 0, 0);"
        char sql[4096] = {0};
        // 将用户名和密码写入sql语句中
        sprintf(sql, INSERT_USER, user["username"].asCString(), user["password"].asCString());
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false)
        {
            LOG(DEBUG, "insert user infomation is failed!\n");
            return false;
        }
        return true;
    }
    // 登录验证，返回详细用户信息
    bool login(Json::Value &user)
    {
        //校验判断用户名和密码存在
        if(user["username"].isNull() || user["password"].isNull())
        {
            LOG(ERROR,"please input username and password!\n");
            return false;
        }
// 以用户名和密码作为查询过滤条件,查询到数据则表示用户密码一致,没有则用户名密码错误
#define LOGIN_USER "select id, score, total_count, win_count from user where username='%s' and password=password('%s');"
        char sql[4096] = {0};
        sprintf(sql, LOGIN_USER, user["username"].asCString(), user["password"].asCString());
        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                // DLOG("user login failed!!\n");
                return false;
            }
            // 按理说要么有数据，要么没有数据，就算有数据也只能有一条数据
            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                // DLOG("have no login user info!!");
                return false;
            }
        }
        int row_num = mysql_num_rows(res);
        if (row_num != 1)
        {
            std::cout << row_num << std::endl;
            LOG(DEBUG, "the user information queried is not unique!!\n");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }
    // 通过用户名获取用户信息
    bool select_by_name(const std::string &name, Json::Value &user)
    {
        // 以用户名和密码作为查询过滤条件,查询到数据则表示用户密码一致,没有则用户名密码错误
#define USER_BY_NAME "select id, score, total_count, win_count from user where username='%s';"
        char sql[4096] = {0};
        sprintf(sql, USER_BY_NAME, name.c_str());
        MYSQL_RES *res = NULL;
        {
            // 执行语句sql
            // 加锁
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                LOG(DEBUG, "get user_by_name failed!\n");
                return false;
            }
            // 有数据或没有数据,有数据也只有一条数据,用户名不能相同
            // 保存数据到本地
            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                LOG(DEBUG, "no user infomation!\n");
                return false;
            }
        }
        // 获取结果集中的行数的函数
        int row_num = mysql_num_rows(res);
        if (row_num != 1)
        {
            LOG(DEBUG, "the user infomation queried is not unique!\n");
            return false;
        }
        // 使用 mysql_fetch_row() 函数在一个循环中从结果集中取得每一行
        // 获取用户信息
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["username"] = name;
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        // 释放结果集
        mysql_free_result(res);
        return true;
    }
    // 通过id获取用户信息
    bool select_by_id(const uint64_t &id, Json::Value &user)
    {
#define USER_BY_ID "select username, score, total_count, win_count from user where id='%ld';"
        char sql[4096] = {0};
        sprintf(sql, USER_BY_ID, id);
        MYSQL_RES *res = NULL;
        {
            // 执行语句sql
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                LOG(DEBUG, "get user_by_id failed!\n");
                return false;
            }
            // 有数据或没有数据,有数据也只有一条数据,用户名不能相同
            // 保存数据到本地
            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                LOG(DEBUG, "no user infomation!\n");
                return false;
            }
        }
        // 获取结果集中的行数的函数
        int row_num = mysql_num_rows(res);
        if (row_num != 1)
        {
            LOG(DEBUG, "the user infomation queried is not unique!\n");
            return false;
        }
        // 使用 mysql_fetch_row() 函数在一个循环中从结果集中取得每一行
        // 获取用户信息
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)id;
        user["username"] = row[0];
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        // 释放结果集
        mysql_free_result(res);
        return true;
    }
    // 胜利时天梯分数增加30，战斗场次增加1，胜利场次增加1
    bool win(uint64_t id)
    {
#define USER_WIN "update user set score=score+30, total_count=total_count+1, win_count=win_count+1 where id='%ld';"
        char sql[4096];
        sprintf(sql, USER_WIN, id);
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false)
        {
            LOG(DEBUG, "update win uer infomation failed!\n");
            return false;
        }
        return true;
    }
    // 失败时天梯分数减少30，战斗场次增加1，其他不变
    bool lose(uint64_t id)
    {
#define USER_LOSE "update user set score=score-30, total_count=total_count+1 where id='%ld';"
        char sql[4096];
        sprintf(sql, USER_LOSE, id);
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false)
        {
            LOG(DEBUG, "update lose uer infomation failed!\n");
            return false;
        }
        return true;
    }
};